﻿using Microsoft.VisualBasic;
using Prism.Commands;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using XH.SmartParking.IService;
using XH.SmartParking.Entities;
using XH.SmartParking.Models;
using XH.SmartParking.Service;

namespace XH.SmartParking.ViewModels.Pages
{
    public class MonitorViewModel : ViewModelBase
    {
        public MonitorModel MonitorModel { get; set; } =
            new MonitorModel();

        public DelegateCommand GotoManagerCommand { get; set; }
        public DelegateCommand LicenseChangedCommand { get; set; }

        IRegionManager _regionManager;
        IDeviceService _deviceService;
        IRecordService _recordService;
        IAutoService _autoService;
        IPayService _payService;
        public MonitorViewModel(
            IRegionManager regionManager,
            IDeviceService deviceService,
            IRecordService recordService,
            IAutoService autoService,
            IPayService payService)
            : base(regionManager)
        {
            _regionManager = regionManager;
            _deviceService = deviceService;
            _recordService = recordService;
            _autoService = autoService;
            _payService = payService;

            //for (var i = 0; i < 10; i++)
            //{
            //    MonitorModel.RecordList.Add(new RecordModel() { Index = (i + 1).ToString() });
            //}
            Refresh();

            GotoManagerCommand = new DelegateCommand(DoGotoManager);
            LicenseChangedCommand = new DelegateCommand(DoLicenseChanged);

            StartMonitor();
        }

        public override void Refresh()
        {
            // 问题：数据实体属性类型与数据库字段类型不匹配
            // 数据库中int32的数字，实体中使用int64的属性类型
            var ri = _recordService.Query<RecordInfo>(r => true)
                .OrderByDescending(r => r.PassTime)
                .ToList();
            for (int i = 0; i < ri.Count(); i++)
            {
                MonitorModel.RecordList.Add(new RecordModel()
                {
                    Index = (i + 1).ToString(),
                    License = ri[i].AutoLicense,
                    PassTime = ri[i].PassTime
                });
            }
        }

        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            base.OnNavigatedTo(navigationContext);

            MonitorModel.CurrentUser = navigationContext.Parameters.GetValue<UserModel>("user");
        }

        private void DoLicenseChanged()
        {
            var new_lic = MonitorModel.License;

            //  手动流程处理
            if (_error_channal == 1)
            {
                // 进入的记录
                EnterRecord(new_lic);

                //MonitorModel.RecordList.Insert(0, new RecordModel { });
            }
            else if (_error_channal == 2)
            {
                // 出场的记录
                ExitRecord(new_lic);
            }

            Refresh();
        }

        private void EnterRecord(string new_lic)
        {
            var ri = _recordService.Insert(new RecordInfo
            {
                AutoLicense = new_lic,
                PassTime = _enterInfo.li.rec_time.ToString(),
                Channal = 1,
                CarColor = _enterInfo.li.item[0].nCarColor,
                LicenseColor = _enterInfo.li.item[0].color,

                ImageFull = _enterInfo.full_file_name,
                ImageSmall = _enterInfo.small_file_name
            });

            // 订单生成
            // 计费模式
            var auto = _autoService.GetAutoByLicense(new_lic);
            _recordService.Insert(new OrderInfo
            {
                AutoLicense = new_lic,
                EnterTime = _enterInfo.li.rec_time.ToString(),
                FeeModeId = auto.FeeModeId,
                State = 0,
                EnterRecord = ri.RecordId
            });

            // 抬杆通知
            DoPass(enter_socket);
        }

        private void ExitRecord(string new_lic)
        {
            // 出场的记录
            var ri = _recordService.Insert(new RecordInfo
            {
                AutoLicense = _exitInfo.li.item[0].license,
                PassTime = _exitInfo.li.rec_time.ToString(),
                Channal = 2,
                CarColor = _exitInfo.li.item[0].nCarColor,
                LicenseColor = _exitInfo.li.item[0].color,

                ImageFull = _exitInfo.full_file_name,
                ImageSmall = _exitInfo.small_file_name
            });
            // 开始费用计算
            var order = _recordService.GetOrderByLicense(_exitInfo.li.item[0].license);

            bool isNeedCalculate = true;
            if (order.FeeModeId == 1)
            {
                isNeedCalculate = false;
            }
            var auto = _autoService.GetAutoByLicense(_exitInfo.li.item[0].license);
            if (new int?[] { 2, 3 }.Contains(order.FeeModeId) &&
                    DateTime.Compare(
                        DateTime.Parse(_exitInfo.li.rec_time.ToString()),// 注意时间转换方法，会报错，参照235行
                        DateTime.Parse(auto.ValidEndTime)// 注意时间转换方法，会报错，参照235行
                    ) <= 0 &&
                    DateTime.Compare(
                        DateTime.Parse(_exitInfo.li.rec_time.ToString()),// 注意时间转换方法，会报错，参照235行
                        DateTime.Parse(auto.ValidStartTime)// 注意时间转换方法，会报错，参照235行
                    ) >= 0)// 年卡/月卡
            {
                //if (DateTime.Parse(li.rec_time.ToString()) <= DateTime.Parse(auto.ValidEndTime) &&
                //    DateTime.Parse(li.rec_time.ToString()) >= DateTime.Parse(auto.ValidStartTime))
                //{

                //}
                // 判断时间是否超时
                // Compare（识别时间，有效结束时间）<0   表示识别时间小于结束时间
                isNeedCalculate = false;
            }
            if (order.FeeModeId == 4 && auto.ValidCount > 0)// 次卡
            {
                isNeedCalculate = false;
            }

            long price = 300;
            long cost = 0;
            if (isNeedCalculate)
            {
                // 进入时间 与  出场时间进行比较   按照特定的费率进行计算费用 
                var rec_time = DateTime.ParseExact(
                        _exitInfo.li.rec_time.ToString(),
                        "yyyyMMddHHmmss",
                        CultureInfo.InvariantCulture);
                var enter_time = DateTime.ParseExact(
                        order.EnterTime.ToString(),
                        "yyyyMMddHHmmss",
                        CultureInfo.InvariantCulture);
                var vv = rec_time - enter_time;
                // 获取两时间之间的所有分钟：半小时之内，不需要计费；超过半小时，按1小时计费
                // 40分钟--1小时   3      0.xxxxxx
                // 1小时1分钟   -  2小时   6   1.xxxxx
                // 1小时31分钟  -  2小时   6   1.xxxxx
                // 2小时1分钟   -  3小时   9   2.xxxxx 
                if (vv.TotalMinutes < 30)
                {
                    // 出场抬杆
                    DoPass(exit_socket);
                }
                else
                {
                    // Math.Ceiling  对一个double值进行向取整操作
                    var h = Math.Ceiling(vv.TotalMinutes / 60);
                    cost = (long)(h * price);
                    order.Payable = cost;
                    order.LeaveTime = _exitInfo.li.rec_time.ToString();

                    cost = 1;// 用于测试，临时使用
                             // 需要调用支付进行处理
                             // 注意：订单号必须4个字符以上，否则生成不了支付链接（主要针对朝夕支付平台）
                             //       金额属于long型，以分为单位
                    string pay_order_id = order.OrderId.ToString() + new Random().Next(100, 999) + order.Payable.ToString();
                    string resp = _payService.Pay(pay_order_id, cost);
                    // json string -> 对象    Json的反序列化
                    var rm = System.Text.Json.JsonSerializer.Deserialize<ResponseMessage>(resp);
                    if (rm.msg == "OK")
                    {
                        string pay_url = rm.value.ToString();
                        // 发送支付链接，对方生成二维码，进行提示，等待支付
                        List<byte> all_bytes = new List<byte>
                            {
                                (byte)'E',(byte)'P',0x00,0x00,
                            };
                        List<byte> url_bytes = new List<byte>
                            {
                                (byte)'E',(byte)'P',0x20,0x00,
                            };
                        byte[] str_bytes = Encoding.UTF8.GetBytes(pay_url);
                        url_bytes.AddRange(BitConverter.GetBytes(str_bytes.Length));
                        url_bytes.AddRange(str_bytes);

                        all_bytes.AddRange(BitConverter.GetBytes(url_bytes.Count()));
                        all_bytes.AddRange(url_bytes);

                        screen_socket.Send(all_bytes.ToArray());

                        while (true)
                        {
                            var state_str = _payService.CheckState(pay_order_id);
                            var state = System.Text.Json.JsonSerializer.Deserialize<ResponseState>(state_str);
                            // state.value - 1  正在支付
                            //               2  支付完成
                            //               3  未找到订单号
                            if (state.value == 2)
                            {
                                // 支付完成
                                // 订单完成
                                order.LeaveTime = _exitInfo.li.rec_time.ToString();
                                order.Payable = cost;
                                order.Payment = cost;
                                order.Discount = 0;
                                order.LeaveRecord = ri.RecordId;

                                order.State = 1;
                                _recordService.Update(order);

                                // 出场抬杆;检查完支付状态之后
                                DoPass(exit_socket);

                                break;
                            }
                        }
                    }
                }
            }
        }

        private async void DoGotoManager()
        {
            // 如何返回到管理后台？
            // 直接从MonitorRegion中移除已有的页面，
            // 首先需要获取到RegionManger对象，通过这个对象进行Region管理

            var region = _regionManager.Regions["MonitorRegion"];
            if (region == null) return;

            var view = region.Views.FirstOrDefault();
            VisualStateManager.GoToElementState((FrameworkElement)view, "CloseState", true);

            await Task.Delay(300);
            region.RemoveAll();
        }

        int _error_channal = 1;
        (LicenseInfo li, string full_file_name, string small_file_name) _enterInfo;
        (LicenseInfo li, string full_file_name, string small_file_name) _exitInfo;
        Socket enter_socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        Socket exit_socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        Socket screen_socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

        private void StartMonitor()
        {
            var ds = _deviceService.Query<DeviceInfo>(d => true).ToList();


            // 屏幕设备连接
            screen_socket.Connect(ds[6].AddrIp, (int)ds[6].AddrPort);


            // 入口设备连接
            enter_socket.SendBufferSize = 1024 * 1024 * 1024;
            enter_socket.ReceiveBufferSize = 1024 * 1024 * 1024;
            enter_socket.Connect(ds[0].AddrIp, (int)ds[0].AddrPort);

            Task.Run(() =>
            {
                while (true)
                {
                    //(LicenseInfo li, string full_file_name, string small_file_name) =
                    _enterInfo = GetLicenseInfo(enter_socket, "I");
                    MonitorModel.License = _enterInfo.li.item[0].license;// ABCDEFG ->  char[]
                    MonitorModel.TipBackground = "OrangeRed";
                    MonitorModel.TipText = "识别异常";

                    if (_enterInfo.li.item[0].nConfidence < 97)
                    {
                        // 手工修改流程
                        _error_channal = 1;
                        continue;
                    }

                    //// 进入的记录
                    //var ri = _recordService.Insert(new RecordInfo
                    //{
                    //    AutoLicense = _enterInfo.li.item[0].license,
                    //    PassTime = _enterInfo.li.rec_time.ToString(),
                    //    Channal = 1,
                    //    CarColor = _enterInfo.li.item[0].nCarColor,
                    //    LicenseColor = _enterInfo.li.item[0].color,

                    //    ImageFull = _enterInfo.full_file_name,
                    //    ImageSmall = _enterInfo.small_file_name
                    //});

                    //// 订单生成
                    //// 计费模式
                    //var auto = _autoService.GetAutoByLicense(_enterInfo.li.item[0].license);
                    //_recordService.Insert(new OrderInfo
                    //{
                    //    AutoLicense = _enterInfo.li.item[0].license,
                    //    EnterTime = _enterInfo.li.rec_time.ToString(),
                    //    FeeModeId = auto.FeeModeId,
                    //    State = 0,
                    //    EnterRecord = ri.RecordId
                    //});

                    //// 抬杆通知
                    ////List<byte> all_bytes = new List<byte>()
                    ////{
                    ////    (byte)'E',(byte)'P',0x00,0x00,   0x00,0x00,0x00,0x08,

                    ////    // 子包头：
                    ////    (byte)'E',(byte)'P',0x0A,0x00,   0x00,0x00,0x00,0x00
                    ////};
                    ////enter_socket.Send(all_bytes.ToArray());
                    //this.DoPass(enter_socket);

                    this.EnterRecord(MonitorModel.License);

                    Refresh();
                }
            });


            // 出口设备连接
            exit_socket.SendBufferSize = 1024 * 1024 * 1024;
            exit_socket.ReceiveBufferSize = 1024 * 1024 * 1024;
            exit_socket.Connect(ds[5].AddrIp, (int)ds[5].AddrPort);
            Task.Run(() =>
            {
                while (true)
                {
                    //(LicenseInfo li, string full_file_name, string small_file_name) =
                    _exitInfo = GetLicenseInfo(exit_socket, "O");
                    MonitorModel.License = _exitInfo.li.item[0].license;// ABCDEFG ->  char[]
                    MonitorModel.TipBackground = "OrangeRed";
                    MonitorModel.TipText = "识别异常";

                    if (_enterInfo.li.item[0].nConfidence < 97)
                    {
                        // 手工修改流程
                        _error_channal = 2;
                        continue;
                    }

                    ExitRecord(MonitorModel.License);

                    Refresh();
                }
            });

        }

        private void DoPass(Socket socket)
        {
            List<byte> all_bytes = new List<byte>()
            {
                (byte)'E',(byte)'P',0x00,0x00,   0x00,0x00,0x00,0x08,

                // 子包头：
                (byte)'E',(byte)'P',0x0A,0x00,   0x00,0x00,0x00,0x00
            };
            socket.Send(all_bytes.ToArray());
        }

        private (LicenseInfo, string, string) GetLicenseInfo(Socket socket, string direction)
        {
            byte[] all_header_bytes = new byte[8];
            socket.Receive(all_header_bytes);
            // 后续所有子包的字节
            int len = BitConverter.ToInt32(all_header_bytes, 4);

            // 将所子包的字节获取到
            byte[] bytes = new byte[len];
            socket.Receive(bytes);

            int index = 0;
            // 识别信息
            byte[] bytes_len = new byte[] {
                        bytes[index+4],
                        bytes[index+5],
                        bytes[index+6],
                        bytes[index+7],
                    };
            len = BitConverter.ToInt32(bytes_len, 0);
            byte[] info_bytes = bytes.ToList().GetRange(index + 8, len).ToArray();
            string info_json = Encoding.UTF8.GetString(info_bytes);
            LicenseInfo li = System.Text.Json.JsonSerializer.Deserialize<LicenseInfo>(info_json);
            index += len + 8;

            // 大图数据
            bytes_len = new byte[] {
                        bytes[index+4],
                        bytes[index+5],
                        bytes[index+6],
                        bytes[index+7],
                    };
            len = BitConverter.ToInt32(bytes_len, 0);
            byte[] full_bytes = bytes.ToList().GetRange(index + 8, len).ToArray();
            index += len + 8;
            // 保存一个图像文件-- 大图
            string full_file_name = $"{li.item[0].license}_{DateTime.Now.ToString("yyyyMMddHHmmss")}_{direction}_full.jpg";
            File.WriteAllBytes("snaps/" + full_file_name, full_bytes);

            // 转成图像对象
            // ImageBrush---ImageSource
            Application.Current.Dispatcher.Invoke(() =>
            {
                using (var ms = new MemoryStream(full_bytes))
                {
                    BitmapImage bi = new BitmapImage();
                    bi.BeginInit();
                    bi.StreamSource = ms;
                    bi.EndInit();
                    bi.Freeze();

                    MonitorModel.EnterSnapFull = bi;
                    ms.Dispose();
                }
            });
            //this.EnterSnapFull = "pack://siteoforigin:,,,/" + file_path;

            // 小图数据 
            bytes_len = new byte[] {
                        bytes[index+4],
                        bytes[index+5],
                        bytes[index+6],
                        bytes[index+7],
                    };
            len = BitConverter.ToInt32(bytes_len, 0);
            byte[] small_bytes = bytes.ToList().GetRange(index + 8, len).ToArray();

            // 保存图像文件--小图
            string small_file_name = $"{li.item[0].license}_{DateTime.Now.ToString("yyyyMMddHHmmss")}_{direction}_small.jpg";
            File.WriteAllBytes("snaps/" + small_file_name, small_bytes);

            // 转成图像对象
            // ImageBrush---ImageSource

            // 这个功能暂时屏蔽
            Application.Current.Dispatcher.Invoke(() =>
            {
                using (var ms = new MemoryStream(small_bytes))
                {
                    BitmapImage bi = new BitmapImage();
                    bi.BeginInit();
                    bi.StreamSource = ms;
                    bi.EndInit();
                    bi.Freeze();

                    MonitorModel.SnapSmall = bi;
                    ms.Dispose();
                }
            });


            return (li, full_file_name, small_file_name);
        }
    }
}
